package org.fujene.communicate;

import org.fujene.structure.SearchRangeTuple;
import org.fujene.structure.TimeRangeTuple;
import org.msgpack.MessagePackObject;
import org.msgpack.object.ArrayType;
import org.msgpack.object.BooleanType;
import org.msgpack.object.IntegerType;
import org.msgpack.object.RawType;

public class SearchFlags{
	private byte[] binaryFlags;
	private TimeRangeTuple timeRange;
	private SearchRangeTuple[] multipleRange;

	private SearchFlags(){}

	public SearchFlags(int binaryFlagSize, int multiFlagSize){
		binaryFlags = new byte[binaryFlagSize];
		timeRange = TimeRangeTuple.dontCare();
		multipleRange = new SearchRangeTuple[multiFlagSize];
	}

	public void setBinaryFlags(int index, boolean isCare, boolean value){
		if(index >= binaryFlags.length) return;
		if(!isCare) binaryFlags[index] = -1;
		else binaryFlags[index] = (byte)(value? 1: 0);
	}

	public void setBinaryFlags(int index, byte value){
		if(index >= binaryFlags.length) return;
		if(value > 1 || value < 0) binaryFlags[index] = -1;
		binaryFlags[index] = value;
	}

	public void setTimeRange(int typeID, long valueFrom, long valueTo){
		switch(typeID){
		case TimeRangeTuple.RANGE_GREATER:
			timeRange = TimeRangeTuple.greaterThan(valueFrom);
			break;
		case TimeRangeTuple.RANGE_LESS:
			timeRange = TimeRangeTuple.lessThan(valueFrom);
			break;
		case TimeRangeTuple.RANGE_EQUAL:
			timeRange = TimeRangeTuple.equalValue(valueFrom);
			break;
		case TimeRangeTuple.RANGE_NOTEQUAL:
			timeRange = TimeRangeTuple.notEqualValue(valueFrom);
			break;
		case TimeRangeTuple.RANGE_RANGE:
			timeRange = TimeRangeTuple.range(valueFrom, valueTo);
			break;
		case TimeRangeTuple.RANGE_NOTRANGE:
			timeRange = TimeRangeTuple.notRange(valueFrom, valueTo);
			break;
		default:
			timeRange = TimeRangeTuple.dontCare();
			break;
		}
	}

	public void setMultipleFlags(int index, int typeID, int valueFrom, int valueTo){
		if(index >= multipleRange.length) return;
		switch(typeID){
		case SearchRangeTuple.RANGE_GREATER:
			multipleRange[index] = SearchRangeTuple.greaterThan(valueFrom);
			break;
		case SearchRangeTuple.RANGE_LESSOREQUAL:
			multipleRange[index] = SearchRangeTuple.lessThan(valueFrom);
			break;
		case SearchRangeTuple.RANGE_EQUAL:
			multipleRange[index] = SearchRangeTuple.equalValue(valueFrom);
			break;
		case SearchRangeTuple.RANGE_NOTEQUAL:
			multipleRange[index] = SearchRangeTuple.notEqualValue(valueFrom);
			break;
		case SearchRangeTuple.RANGE_RANGE:
			multipleRange[index] = SearchRangeTuple.range(valueFrom, valueTo);
			break;
		case SearchRangeTuple.RANGE_NOTRANGE:
			multipleRange[index] = SearchRangeTuple.notRange(valueFrom, valueTo);
			break;
		default:
			multipleRange[index] = SearchRangeTuple.dontCare();
			break;
		}
	}

	public byte[] getBinaryFlags(){
		return binaryFlags;
	}

	public TimeRangeTuple getTimeRange(){
		return timeRange;
	}

	public SearchRangeTuple[] getFlagRange(){
		return multipleRange;
	}

	public static SearchFlags fromMessage(ArrayType message){
		MessagePackObject[] objs = message.asArray();
		SearchFlags flags = new SearchFlags();

		flags.binaryFlags = objs[0].asByteArray();
		flags.multipleRange = new SearchRangeTuple[(objs.length - 4) / 3];
		flags.timeRange = TimeRangeTuple.fromMessage(objs[1].asLong(), objs[2].asLong(), objs[3].asBoolean());
		for(int i = 0; i < flags.multipleRange.length; i++){
			flags.multipleRange[i] =
				SearchRangeTuple.fromMessage(objs[3 * i + 4].asInt(), objs[3 * i + 5].asInt(),
					objs[3 * i + 6].asBoolean());
		}

		return flags;
	}

	public ArrayType toMessage(){
		MessagePackObject[] msg = new MessagePackObject[3 * multipleRange.length + 4];
		msg[0] = RawType.create(binaryFlags);
		msg[1] = IntegerType.create(timeRange.rangeFrom());
		msg[2] = IntegerType.create(timeRange.rangeTo());
		msg[3] = BooleanType.create(timeRange.equalToFrom());
		for(int i = 0; i < multipleRange.length; i++){
			msg[3 * i + 4] = IntegerType.create(multipleRange[i].rangeFrom());
			msg[3 * i + 5] = IntegerType.create(multipleRange[i].rangeTo());
			msg[3 * i + 6] = BooleanType.create(multipleRange[i].equalToFrom());
		}

		return ArrayType.create(msg);
	}
}
